Skip to content

Conversation

@everettbu
Copy link
Contributor

Test 10

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR implements a fix for concurrent group access issues to prevent NullPointerExceptions in Keycloak's group management system. The changes span across multiple layers of the architecture:

  1. Caching Layer Enhancement: In CachedGroup.java, the @Override annotation is added to the getRealm() method to ensure proper interface implementation compliance with the InRealm interface, improving code maintainability and compile-time verification.

  2. Group Adapter Null Safety: The GroupAdapter.java file receives a critical fix in the getSubGroupsCount() method, where null-safety is added by checking if the model from modelSupplier.get() is null before calling operations on it. This prevents NPEs in concurrent scenarios where groups might be deleted while other threads access them.

  3. GroupUtils Refactoring: The GroupUtils.java class has the groupMatchesSearchOrIsPathElement method removed as part of the broader refactoring. This appears to consolidate functionality and eliminate potentially redundant code paths.

  4. Comprehensive Test Coverage: A new concurrency test createMultiDeleteMultiReadMulti() is added to GroupTest.java that creates 100 groups, performs concurrent read operations in a background thread while deletion is happening, and verifies no exceptions occur. This serves as a regression test for the concurrent access fixes.

These changes work together to address race conditions in Keycloak's group caching and access mechanisms, particularly in Infinispan-based implementations where concurrent modifications can lead to inconsistent states.

Confidence score: 2/5

  • This PR has significant null safety issues that could cause immediate production problems
  • While the caching layer fix is solid, the GroupUtils.java file still contains multiple potential NullPointerExceptions that weren't addressed
  • Files needing more attention: services/src/main/java/org/keycloak/utils/GroupUtils.java contains unaddressed NPE risks on lines 47 and 71

4 files reviewed, 3 comments

Edit Code Review Bot Settings | Greptile

Comment on lines +274 to 276
GroupModel model = modelSupplier.get();
return model == null ? null : model.getSubGroupsCount();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: This pattern differs from other methods like getSubGroupsStream() which call getDelegateForUpdate() when encountering null models. Consider consistency with the existing error handling pattern.

Comment on lines +139 to +149
new Thread(() -> {
while (!deletedAll.get()) {
try {
// just loading briefs
managedRealm.admin().groups().groups(null, 0, Integer.MAX_VALUE, true);
} catch (Exception e) {

caughtExceptions.add(e);
}
}
}).start();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Thread is started but not joined, creating a race condition where the test might complete before the reader thread finishes executing

Suggested change
new Thread(() -> {
while (!deletedAll.get()) {
try {
// just loading briefs
managedRealm.admin().groups().groups(null, 0, Integer.MAX_VALUE, true);
} catch (Exception e) {
caughtExceptions.add(e);
}
}
}).start();
Thread readerThread = new Thread(() -> {
while (!deletedAll.get()) {
try {
// just loading briefs
managedRealm.admin().groups().groups(null, 0, Integer.MAX_VALUE, true);
} catch (Exception e) {
caughtExceptions.add(e);
}
}
});
readerThread.start();
// delete groups
groupUuuids.forEach(groupUuid -> {
managedRealm.admin().groups().group(groupUuid).remove();
});
deletedAll.set(true);
try {
readerThread.join(5000); // Wait up to 5 seconds for thread to complete
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
fail("Test interrupted while waiting for reader thread");
}

@Test
public void createMultiDeleteMultiReadMulti() {
// create multiple groups
List<String> groupUuuids = new ArrayList<>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Variable name has typo: groupUuuids should be groupUuids

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants